package lime.agent;

import java.util.Vector;

import emulator.peers.*;
import emulator.agent.*;

import eventengine.middleware.*;

import tota.tuples.hop.GradientTuple;
import tuplespace.tuples.*;

import lime.middleware.*;

public class AgentLimeEXP extends AbstractAgent {
	static int BOOT_DELAY = 5;

	static boolean REALTIME_SCREEN_UPDATE = true;

	LimeInterface lime;

	private PeerInterface_ApplicationSide peer;

	Vector perceivedLocalTuples = new Vector();

	Vector perceivedRemoteTuples = new Vector();

	private EventInterface tsEvent;

	private EventInterface vtsEvent;

	public AgentLimeEXP(PeerInterface_ApplicationSide peer) {
		this.peer = peer;
		// lime = (LimeInterface)new limefast.middleware.LimeFast(peer);
		lime = (LimeInterface) new Lime(peer);

		/*
		 * create event server and make subsciptions to the lime middleware to
		 * get notified about tupels being inserted and removed
		 */
		tsEvent = new EventServer("AgentLime" + peer.toString() + "TS");
		vtsEvent = new EventServer("AgentLime" + peer.toString() + "VTS");
		lime.setOutsideEvent(tsEvent, vtsEvent);

		TsTuple in = new TsTuple("<op=IN><tuple=*>");
		TsTuple out = new TsTuple("<op=OUT><tuple=*>");

		tsEvent.subscribe(in, this, "LOCAL_IN");
		tsEvent.subscribe(out, this, "LOCAL_OUT");

		vtsEvent.subscribe(in, this, "REMOTE_IN");
		vtsEvent.subscribe(out, this, "REMOTE_OUT");
	}

	public String toString() {
		return new String("agentLime on " + lime.toString());
	}

	/** ************************************************************************** */
	/* AGENT OWN ACTIONS */
	/** ************************************************************************** */
	public void write(String content) {
		Tuple t = (Tuple) new Tuple(content);
		lime.write(t);
	}

	public void extract(String content) {
		Tuple t = new Tuple(content);
		lime.extract(t);
	}

	public void keyextract(String content) {
		Tuple t = new Tuple(content);
		lime.keyextr(t);
	}

	/** ************************************************************************** */
	/* REACTIVE METHOD */
	/** ************************************************************************** */
	public void react(String reaction, String event) {
		if (reaction.equalsIgnoreCase("LOCAL_IN")) {
			TsTuple ts = (TsTuple) Tuple.deserialize(event);
			Tuple t = Tuple.deserialize(ts.tuple);
			perceivedLocalTuples.add(t);
		} else if (reaction.equalsIgnoreCase("LOCAL_OUT")) {
			TsTuple ts = (TsTuple) Tuple.deserialize(event);
			Tuple t = Tuple.deserialize(ts.tuple);
			perceivedLocalTuples.remove(t);
		} else if (reaction.equalsIgnoreCase("REMOTE_IN")) {
			TsTuple ts = (TsTuple) Tuple.deserialize(event);
			Tuple t = Tuple.deserialize(ts.tuple);
			perceivedRemoteTuples.add(t);
		} else if (reaction.equalsIgnoreCase("REMOTE_OUT")) {
			TsTuple ts = (TsTuple) Tuple.deserialize(event);
			Tuple t = Tuple.deserialize(ts.tuple);
			perceivedRemoteTuples.remove(t);
		}
	}

	
	private void printTuples(int time) {
		System.out.println("*** " + time + ": " + peer.getAddress());
		
		Tuple all = new Tuple("<content=*>");
		
		// read own tuple space
		Vector v = lime.read(all);
		for (int i = 0; i < v.size(); i++)
			System.out.println("own " + ((GradientTuple) v.get(i)).hop);
		// read neighbor tuple space
		Vector vn = lime.rdOneHop(all);
		for (int i = 0; i < vn.size(); i++)
			System.out.println("neigh " + ((GradientTuple) vn.get(i)).hop);
	}

	/** ************************************************************************** */
	/* AGENT INTERFACE METHODS */
	/***************************************************************************
	 * These metohds wouldn't be actually required by the real agents that
	 * simply would display this panel in their user interface. However they are
	 * needed for /
	 **************************************************************************/
	public void step(int time) {

		lime.step(time);

		/*
		 * TIME = 10 The node 0 injects a hop tuple
		 */

		if (time == 10) {

			if (peer.getAddress().equals("192.168.0.0")) {
				System.out.println("\n\n\n");
				inject("hop.GradientTuple", "<content=ciao>");
			}

		}

		if (time == 90)
			printTuples(time);

		/*
		 * TIME = 100 The node 0 moves out of the network
		 */

		if (time == 100) {

			if (peer.getAddress().equals("192.168.0.0")) {
				System.out.println("\n\n\n");
				move(300, 300);
			}
		}

		if (time == 290)
			printTuples(time);

		/*
		 * TIME = 300 The node 0 moves on the other side of the network
		 */

		if (time == 300) {

			if (peer.getAddress().equals("192.168.0.0")) {
				System.out.println("\n\n\n");
				move(475, 100);
			}

		}

		if (time == 490)
			printTuples(time);

		/*
		 * TIME = 500 The node 0 moves out of the network
		 */

		if (time == 500) {

			if (peer.getAddress().equals("192.168.0.0")) {
				System.out.println("\n\n\n");
				move(300, 300);
			}
		}

		if (time == 690)
			printTuples(time);

		/*
		 *  // TIME = 700 The node 0 moves at the begining of the network
		 * 
		 * 
		 * if (time == 700) {
		 * 
		 * if(peer.getAddress().equals("192.168.0.0")) {
		 * System.out.println("\n\n\n"); move(100, 100); } }
		 * 
		 * 
		 * if(time == 890) printTuples(time);
		 * 
		 * 
		 *  // TIME = 900 The node 0 moves out of the network
		 * 
		 * 
		 * if (time == 900) {
		 * 
		 * if(peer.getAddress().equals("192.168.0.0")) {
		 * System.out.println("\n\n\n"); move(300, 300); } }
		 */

	}

	public synchronized void showAgentFrame() {
	}

	public synchronized void hideAgentFrame() {
		peer.shutDown();
	}

	public synchronized Object getRealIdentity() {
		return this;
	}
}